import config from "@/config";
import md5 from 'js-md5';
// 全局socket
let socket = null;
// 连接状态
let isConnected = false;
// 当前重连次数
let reconnectCount = 0;
// 最大重连次数
const MAX_RECONNECT_COUNT = 5;
// 重连间隔（毫秒）
const RECONNECT_INTERVAL = 5000;
// 重连定时器
let reconnectTimer = null;
// 是否正在重连
let isReconnecting = false;

/**
 * 生成随机字符串
 * @param {number} length 随机字符串长度
 * @returns {string} 随机字符串
 */
function generateNonce(length = 16) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  let result = '';
  for (let i = 0; i < length; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return result;
}

/**
 * 生成签名
 * @param {string} timestamp 时间戳
 * @param {string} nonce 随机数
 * @param {string} uid 用户ID
 * @param {string} secretKey 密钥
 * @returns {string} 签名
 */
function generateSignature(timestamp, nonce, uid, secretKey = '') {
  // 如果没有密钥，使用默认密钥
  if (!secretKey) {
    secretKey = config.wsSecretKey || 'default_secret_key';
  }
  
  // 按字典序排序参数
  const params = {
    timestamp,
    nonce,
    uid,
    secretKey
  };
  
  // 构建签名字符串
  const signString = Object.keys(params)
    .sort()
    .map(key => `${key}=${params[key]}`)
    .join('&');
  
  // 使用更安全的哈希算法
  return simpleHash(signString);
}

/**
 * 简单的哈希函数（生产环境建议使用crypto-js等库）
 * @param {string} str 待哈希的字符串
 * @returns {string} 哈希值
 */
function simpleHash(str) {
  let hash = 0;
  if (str.length === 0) return hash.toString(16);
  
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash = hash & hash; // 转换为32位整数
  }
  
  return Math.abs(hash).toString(16);
}

/**
 * 验证签名
 * @param {string} timestamp 时间戳
 * @param {string} nonce 随机数
 * @param {string} uid 用户ID
 * @param {string} signature 签名
 * @param {string} secretKey 密钥
 * @returns {boolean} 验证结果
 */
function verifySignature(timestamp, nonce, uid, signature, secretKey = '') {
  if (!timestamp || !nonce || !uid || !signature) {
    return false;
  }
  
  // 检查时间戳是否过期
  const now = Date.now();
  const timestampNum = parseInt(timestamp);
  const timeout = config.wsAuthTimeout || 30000;
  
  if (now - timestampNum > timeout) {
    console.warn('WebSocket验签超时');
    return false;
  }
  
  // 生成期望的签名
  const expectedSignature = generateSignature(timestamp, nonce, uid, secretKey);
  return expectedSignature === signature;
}

/**
 * 获取验签参数
 * @param {string} uid 用户ID
 * @returns {object} 验签参数对象
 */
function getAuthParams(uid) {
  const timestamp = Date.now().toString();
  const nonce = generateNonce();
  const signature = md5("timestamp="+timestamp+"&nonce="+nonce+"&01e553a3697a0479bac95466cea61487e1dba680").toString();

  return {
    timestamp,
    nonce,
    signature
  };
}

// 初始化WebSocket
export function initWebSocket(uid, isReconnect = false) {
  return new Promise((resolve, reject) => {
    // 如果已有连接，先关闭
    if (socket) {
      closeWebSocket();
    }

    // 如果是重连，检查重连次数
    if (isReconnect) {
      console.log(`WebSocket第${reconnectCount}次重连尝试`);
    } else {
      // 新连接，重置重连计数
      reconnectCount = 0;
    }

    // 获取验签参数
    const authParams = getAuthParams(uid);
    // console.log('WebSocket验签参数:', authParams);

    // 创建WebSocket连接
    socket = uni.connectSocket({
      url: `${config.wsUrl}?timestamp=${authParams.timestamp}&nonce=${authParams.nonce}&signature=${authParams.signature}`,
      success: (res) => {
        // 这里只是创建了连接对象，并不代表真正的连接成功
        console.log("WebSocket连接创建成功", res);
      },
      fail: (err) => {
        console.error("WebSocket连接创建失败", err);
        // 移除自动重连
        reject(err);
      },
    });

    // 添加 onOpen 监听器
    socket.onOpen(() => {
      console.log("WebSocket连接已打开，状态为 OPEN");
      // clearTimeout(connectionTimeout); // 移除超时定时器清除
      isConnected = true;
      isReconnecting = false;
      if (reconnectTimer) {
        clearTimeout(reconnectTimer);
        reconnectTimer = null;
      }
      sendHeartbeatMessage(uid);
      resolve(socket);
    });

    // 监听连接关闭
    socket.onClose(() => {
      console.log("WebSocket连接已关闭");
      isConnected = false;
    });

    // 监听错误
    socket.onError((err) => {
      console.error("WebSocket连接错误", err);
      isConnected = false;
      if (!isReconnect) {
        reject(err);
      }
    });

    // 监听消息
    socket.onMessage((res) => {
      // console.log("收到WebSocket消息", res);
      
      // 检查消息数据是否存在
      if (!res.data) {
        console.warn('WebSocket消息数据为空');
        return;
      }
      
      // 检查消息数据是否为字符串
      if (typeof res.data !== 'string') {
        console.warn('WebSocket消息数据不是字符串格式:', typeof res.data, res.data);
        return;
      }
      
      // 检查消息数据是否为空字符串
      if (res.data.trim() === '') {
        console.warn('WebSocket消息数据为空字符串');
        return;
      }
      
      try {
        // 尝试解析JSON
        let data = JSON.parse(res.data);
        
        // 验证消息签名（如果消息包含auth信息）
        if (data.auth) {
          const { timestamp, nonce, uid: msgUid, signature } = data.auth;
          if (!verifySignature(timestamp, nonce, msgUid, signature)) {
            console.warn('WebSocket消息验签失败，忽略此消息');
            return;
          }
        }
        
        // 消息类型
        let type = data.type || data.data;
        // 根据不同的消息类型做不同处理
        switch (type) {
          case "heartbeat":
            // 心跳消息已经由定时任务维护，这里不做处理
            break;
          case "timeout":
            // 超时断开，尝试重连 - 只在这里重连
            scheduleReconnect(uid);
            break;
          case "error":
            // 错误消息，用于后端返回错误信息，前端对应做错误处理，无实质性逻辑
            break;
          case "auth_failed":
            // 验签失败，关闭连接
            console.error('WebSocket验签失败，关闭连接');
            closeWebSocket();
            break;
          case "pull_location":
            // TODO: 收到用户的坐标信息，前端对应做坐标显示处理
            console.log("收到用户的坐标信息：", data, JSON.stringify(data));
            // uni.$emit('locationsMessagesChanged', data.message.locations);
            break;
          case "MATERIAL_PRICE":
            try {
              // console.log(120, 'WebSocket收到物料价格消息', data.msg);
              // 检查data.msg是否存在且为字符串
              if (data.msg && typeof data.msg === 'string') {
                const priceData = JSON.parse(data.msg);
                // console.log(121, 'WebSocket收到物料价格消息', priceData);
                // 发送价格更新事件，包含实时数据
                uni.$emit("priceMessagesChanged", {
                  data: priceData,
                });
                
                // 自动存储物料价格到本地
                if (priceData.materialType) {
                  import('./materialStorage.js').then(({ saveMaterialPrice }) => {
                    saveMaterialPrice(priceData.materialType, priceData);
                  }).catch(err => {
                    console.error('导入物料存储模块失败:', err);
                  });
                }
                
              } else if (data.msg && typeof data.msg === 'object') {
                // 如果msg已经是对象，直接使用
                uni.$emit("priceMessagesChanged", {
                  data: data.msg,
                });
                
                // 自动存储物料价格到本地
                if (data.msg.materialType) {
                  import('./materialStorage.js').then(({ saveMaterialPrice }) => {
                    saveMaterialPrice(data.msg.materialType, data.msg);
                  }).catch(err => {
                    console.error('导入物料存储模块失败:', err);
                  });
                }
                
              } else {
                console.warn('物料价格消息格式不正确:', data.msg);
              }
            } catch (parseError) {
              console.error('解析价格数据失败:', parseError, '原始数据:', data.msg);
              // 如果解析失败，发送原始数据
              uni.$emit("priceMessagesChanged", {
                type: 'raw',
                data: data.msg,
              });
            }
            break;
          default:
            // 记录未知消息类型，便于调试
            console.log('收到未知类型的WebSocket消息:', type, data);
            break;
        }
      } catch (error) {
        console.error('解析WebSocket消息失败:', error);
        console.error('原始消息数据:', res.data);
        console.error('消息数据类型:', typeof res.data);
        
        // 尝试处理非JSON格式的消息
        handleNonJsonMessage(res.data);
      }
    });
  });
}

/**
 * 重连调度函数 - 只在收到timeout消息时调用
 */
export function scheduleReconnect(uid) {
  // 如果正在重连，或者重连次数大于等于最大重连次数，则不进行重连
  if (isReconnecting || reconnectCount >= MAX_RECONNECT_COUNT) {
    if (reconnectCount >= MAX_RECONNECT_COUNT) {
      console.error(`已达到最大重连次数 ${MAX_RECONNECT_COUNT}，停止重连`);
    }
    return;
  }

  // 设置正在重连
  isReconnecting = true;
  // 递增重连次数
  reconnectCount++;

  console.log(`${RECONNECT_INTERVAL}ms后进行第${reconnectCount}次重连`);

  // 设置重连定时器
  reconnectTimer = setTimeout(() => {
    console.log("开始执行重连...");
    initWebSocket(uid, true).catch((err) => {
      console.error("重连失败:", err);
      // 重连失败后，重置重连状态，允许下次重连
      isReconnecting = false;
    });
  }, RECONNECT_INTERVAL);
}

/**
 * 发送消息基础方法，所有消息都通过这个方法发送
 * @param {*} type 消息类型 心跳消息：heartbeat，文本消息：text，错误消息：error，超时断开：timeout，推送坐标：push_location，拉取坐标：pull_location
 * @param {*} message 消息内容 根据不同业务传递不同格式的数据，与后端约定
 * @param {*} uid 用户ID，用于生成消息签名
 * @returns
 */
export function sendMessage(type, message, uid = '') {
  return new Promise((resolve, reject) => {
    // 检查连接状态
    if (!isWebSocketConnected()) {
      // console.error('WebSocket未连接');
      return;
    }
    try {
      // 生成消息签名
      const timestamp = Date.now().toString();
      const nonce = generateNonce(8);
      const messageSignature = generateSignature(timestamp, nonce, uid);
      
      // 定义数据格式，包含验签信息
      const data = JSON.stringify({
        type: type,
        message: message,
        auth: {
          timestamp: timestamp,
          nonce: nonce,
          signature: messageSignature,
          uid: uid
        }
      });
      
      // 发送消息
      socket.send({
        data: data,
        success: () => {
          // console.log('消息发送成功');
          resolve();
        },
        fail: (err) => {
          // console.error('消息发送失败', err);
          reject(err);
        },
      });
    } catch (error) {
      console.error("发送消息时出错", error);
      reject(error);
    }
  });
}

// 检查连接状态
export function isWebSocketConnected() {
  return isConnected && socket;
}

// 关闭连接
export function closeWebSocket() {
  if (socket) {
    socket.close();
    socket = null;
    isConnected = false;
  }
  // 清理重连相关状态
  isReconnecting = false;
  if (reconnectTimer) {
    clearTimeout(reconnectTimer);
    reconnectTimer = null;
  }
}

/**
 * 发送心跳消息
 * 数据格式：{"type":"heartbeat","message":{"from_uid":"发送者ID","to_uid":0,"line_id":0,"message_type":"text","message_content":"ping"}}
 * @param {*} uid 发送者ID
 */
export function sendHeartbeatMessage(uid) {
  sendMessage("heartbeat", {
    from_uid: uid,
    to_uid: 0,
    line_id: 0,
    message_type: "text",
    message_content: "ping",
  }, uid);
}

/**
 * 推送坐标
 * fix: 数据格式：{"type":"push_location","message":{"from_uid":"发送者ID","phone":"手机号","avatar":"头像","longitude":"经度","latitude":"纬度"}}
 */
export function pushLocation(uid, phone, avatar, longitude, latitude) {
  sendMessage("push_location", {
    from_uid: uid,
    phone: phone,
    avatar: avatar,
    longitude: longitude,
    latitude: latitude,
  }, uid);
}

/**
 * 拉取坐标
 * 传递数据格式：{"type":"pull_location","message":{"uids":["用户id1","用户id2","用户id3"]}}
 * 返回数据格式：{"type":"pull_location","message":{"locations":[{"id":4,"longitude":"104.043263","latitude":"30.641896"},{"id":5,"longitude":"","latitude":""}]}}
 */
export function pullLocation(uids, uid) {
  sendMessage("pull_location", {
    uids: uids,
  }, uid);
}

/**
 * 发送文本消息
 * 传递数据格式：{"type":"text","message":{"from_uid":"发送者ID","to_uid":接收者ID,"line_id":线路ID,"message_type":"text","message_content":"消息内容"}}
 */
export function sendTextMessage(
  from_uid,
  to_uid,
  line_id,
  message_content,
  message_type = "text"
) {
  sendMessage("text", {
    from_uid: from_uid,
    to_uid: to_uid,
    line_id: line_id,
    message_type: message_type,
    message_content: message_content,
  }, from_uid);
}

/**
 * 获取socket对象
 * @returns
 */
export function getSocket() {
  return socket;
}

/**
 * 获取当前连接状态
 * @returns {boolean} 连接状态
 */
export function getConnectionStatus() {
  return isConnected;
}

/**
 * 获取当前重连次数
 * @returns {number} 重连次数
 */
export function getReconnectCount() {
  return reconnectCount;
}

/**
 * 手动重连（用于验签失败等情况）
 * @param {string} uid 用户ID
 */
export function manualReconnect(uid) {
  console.log('手动重连WebSocket');
  closeWebSocket();
  reconnectCount = 0;
  isReconnecting = false;
  return initWebSocket(uid, false);
}

/**
 * 验证WebSocket连接的有效性
 * @returns {boolean} 连接是否有效
 */
export function validateConnection() {
  if (!isConnected || !socket) {
    return false;
  }
  
  // 检查连接是否超时
  const now = Date.now();
  // 这里可以添加更多的连接有效性检查
  
  return true;
}

/**
 * 处理非JSON格式的WebSocket消息
 * @param {string} message 原始消息内容
 */
export function handleNonJsonMessage(message) {
  try {
    // 尝试处理纯文本消息
    if (message.includes('连')) {
      console.log('收到连接相关消息:', message);
      // 这里可以添加连接状态处理逻辑
      return;
    }
    
    // 尝试处理其他格式的消息
    if (message.includes('price') || message.includes('价格')) {
      console.log('收到价格相关消息:', message);
      // 尝试提取价格信息
      extractPriceFromText(message);
      return;
    }
    
    // 记录无法识别的消息
    console.warn('无法识别的WebSocket消息格式:', message);
    
  } catch (error) {
    console.error('处理非JSON消息失败:', error);
  }
}
  
/**
 * 从文本中提取价格信息
 * @param {string} text 文本内容
 */
export function extractPriceFromText(text) {
  try {
    // 这里可以添加文本解析逻辑，提取价格信息
    // 例如：使用正则表达式匹配价格数据
    console.log('尝试从文本中提取价格信息:', text);
    
    // 如果无法提取，发送原始消息
    uni.$emit("priceMessagesChanged", {
      type: 'text',
      data: { message: text },
    });
    
  } catch (error) {
    console.error('提取价格信息失败:', error);
  }
}
